from typing import Annotated, AsyncGenerator

from fastapi import Depends
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker

from dc_shop.database.services import BotSettingsService
from dc_shop.database.services.discount import DiscountService
from dc_shop.database.services.order import OrderService
from dc_shop.database.services.product import ProductService
from dc_shop.database.services.promocode import PromocodeService
from dc_shop.database.services.shop import ShopService
from dc_shop.database.services.user import UserService
from dc_shop.database.uow import SQLAlchemyUoW
from dc_shop.database.uow.uow import build_uow
from dc_shop.webapp.app.providers.stub import Stub


class InfraProvider:
    def __init__(
        self,
        session_factory: async_sessionmaker[AsyncSession],
    ) -> None:
        self._pool = session_factory

    async def get_uow(self) -> AsyncGenerator[SQLAlchemyUoW, None]:
        async with self._pool() as session:
            uow = build_uow(session)
            yield uow


async def get_user_service(
    uow: Annotated[SQLAlchemyUoW, Depends(Stub(SQLAlchemyUoW))],
) -> UserService:
    yield UserService(uow=uow)


async def get_product_service(
    uow: Annotated[SQLAlchemyUoW, Depends(Stub(SQLAlchemyUoW))],
) -> ProductService:
    yield ProductService(uow=uow)


async def get_shop_service(
    uow: Annotated[SQLAlchemyUoW, Depends(Stub(SQLAlchemyUoW))],
) -> ShopService:
    yield ShopService(uow=uow)


async def get_discount_service(
    uow: Annotated[SQLAlchemyUoW, Depends(Stub(SQLAlchemyUoW))],
) -> DiscountService:
    yield DiscountService(uow=uow)


async def get_order_service(
    uow: Annotated[SQLAlchemyUoW, Depends(Stub(SQLAlchemyUoW))],
) -> OrderService:
    yield OrderService(uow=uow)


async def get_promocode_service(
    uow: Annotated[SQLAlchemyUoW, Depends(Stub(SQLAlchemyUoW))],
) -> PromocodeService:
    yield PromocodeService(uow=uow)


async def get_bot_settings_service(
    uow: Annotated[SQLAlchemyUoW, Depends(Stub(SQLAlchemyUoW))],
) -> BotSettingsService:
    yield BotSettingsService(uow=uow)
